from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from sqlalchemy.orm import selectinload
from datetime import datetime
from typing import Optional, List

from app.db.models import User, URL, Click
from app.core.security import get_password_hash, verify_password

class CRUDUser:
    async def create(self, db: AsyncSession, *, email: str, password: str) -> User:
        db_user = User(
            email=email,
            hashed_password=get_password_hash(password)
        )
        db.add(db_user)
        await db.commit()
        await db.refresh(db_user)
        return db_user

    async def get_by_email(self, db: AsyncSession, email: str) -> Optional[User]:
        result = await db.execute(select(User).where(User.email == email))
        return result.scalar_one_or_none()

class CRUDURL:
    async def create(
        self, 
        db: AsyncSession, 
        *, 
        original_url: str, 
        short_code: str,
        owner_id: int,
        expires_at: Optional[datetime] = None
    ) -> URL:
        db_url = URL(
            original_url=original_url,
            short_code=short_code,
            owner_id=owner_id,
            expires_at=expires_at
        )
        db.add(db_url)
        await db.commit()
        await db.refresh(db_url)
        return db_url

    async def get_by_short_code(self, db: AsyncSession, short_code: str) -> Optional[URL]:
        result = await db.execute(
            select(URL)
            .where(URL.short_code == short_code)
            .options(selectinload(URL.owner))
        )
        return result.scalar_one_or_none()

    async def check_code(self, code: str, db: AsyncSession) -> bool:
        """检查短码是否在数据库中存在"""
        result = await db.execute(select(URL).where(URL.short_code == code))
        return result.scalar_one_or_none() is not None

class CRUDClick:
    async def create(
        self,
        db: AsyncSession,
        *,
        url_id: int,
        ip_address: str,
        user_agent: str
    ) -> Click:
        db_click = Click(
            url_id=url_id,
            ip_address=ip_address,
            user_agent=user_agent
        )
        db.add(db_click)
        await db.commit()
        await db.refresh(db_click)
        return db_click

user = CRUDUser()
url = CRUDURL()
click = CRUDClick() 